import { nanoid } from "nanoid";

type FetchHttpMethod =
  | "GET"
  | "HEAD"
  | "PATCH"
  | "POST"
  | "PUT"
  | "DELETE"
  | "CONNECT"
  | "OPTIONS"
  | "TRACE"
  | "get"
  | "head"
  | "patch"
  | "post"
  | "put"
  | "delete"
  | "connect"
  | "options"
  | "trace";

const header = (url: string) => {
  //   const { token } = url.startsWith("/admin") ? useAdminAuth() : useAuth();
  const token = ref("");
  const h: any = { "Content-Type": "application/json" };
  if (token && token.value) {
    h["Authorization"] = `Bearer ${token.value}`;
  }
  h["X-Path"] = url;
  return { ...h };
};

const body = (body?: any) => {
  if (body) {
    return JSON.stringify(body);
  }
  return body;
};

export default function use$fetch() {
  const baseURL = useRuntimeConfig().public.apiUrl;
  const { throwApiErr, isApiErr } = use$apiErr();
  const { isLoading } = use$status();

  const _fetch = async <T>(
    url: string,
    options: {
      method?: FetchHttpMethod;
      body?: any;
      onSuccess?: (v: T | null) => T | null;
      query?: Record<string, any>;
      hiddenLoading?: boolean;
    }
  ) => {
    if (options.hiddenLoading !== true) {
      isLoading.value = true;
    }
    return useAsyncData(nanoid(), () =>
      $fetch<T>(url, {
        method: options.method,
        baseURL,
        body: body(options.body),
        headers: header(url),
        query: options.query,
        timeout: 3000,
      }).then((v) => {
        try {
          const resp = v as ApiResp<T>;
          if (resp.code !== 0) {
            throwApiErr(resp.msg);
          }
          if (options.onSuccess) {
            return options.onSuccess(resp.data);
          }
          return resp.data;
        } catch (e) {
        } finally {
          isLoading.value = false;
        }
      })
    );
  };

  const $get = async <T>(
    url: string,
    onSuccess?: (v: T | null) => T | null,
    hiddenLoading?: boolean,
    query?: Record<string, any>
  ) => await _fetch<T>(url, { method: "GET", onSuccess, query, hiddenLoading });

  const $post = async <T>(
    url: string,
    body?: any,
    onSuccess?: (v: T | null) => T | null,
    hiddenLoading?: boolean
  ) => await _fetch<T>(url, { method: "POST", body, onSuccess, hiddenLoading });

  const $put = async <T>(
    url: string,
    body?: any,
    onSuccess?: (v: T | null) => T | null
  ) => await _fetch<T>(url, { method: "PUT", body, onSuccess });

  const $patch = async <T>(
    url: string,
    body?: any,
    onSuccess?: (v: T | null) => T | null
  ) => await _fetch<T>(url, { method: "PATCH", body, onSuccess });

  const $del = async <T>(url: string, onSuccess?: (v: T | null) => T | null) =>
    await _fetch<T>(url, { method: "DELETE", onSuccess });

  return { $get, $post, $put, $patch, $del };
}
